using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using RideMe.Core.Properties;

namespace RideMe.Core
{
    public class Testing
    {
        private RakeProcess _rake;
        private RubyProcess _ruby;

        public Testing(RubyProcess ruby, RakeProcess rake)
        {
            _ruby = ruby;
            _ruby.Completed += new EventHandler(process_Completed);
            _ruby.OutputReceived += new EventHandler<DataReceivedEventArgs>(process_OutputReceived);
            _ruby.ErrorReceived += new EventHandler<DataReceivedEventArgs>(process_ErrorReceived);
            
            _rake = rake;
            _rake.Completed += new EventHandler(process_Completed);
            _rake.OutputReceived += new EventHandler<DataReceivedEventArgs>(process_OutputReceived);
            _rake.ErrorReceived += new EventHandler<DataReceivedEventArgs>(process_ErrorReceived);
        }
        
        public Testing() : this(new RubyProcess(), new RakeProcess())
        {
        }

        void process_ErrorReceived(object sender, DataReceivedEventArgs e)
        {
            OnErrorReceived(e);
        }

        public event EventHandler<DataReceivedEventArgs> OutputReceived;
        public event EventHandler Completed;
        public event EventHandler<DataReceivedEventArgs> ErrorReceived;

        /// <summary>
        /// Raises the output received event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.Diagnostics.DataReceivedEventArgs"/> instance containing the event data.</param>
        private void OnOutputReceived(DataReceivedEventArgs e)
        {
            if (OutputReceived != null)
            {
                OutputReceived(this, e);
            }
        }

        /// <summary>
        /// Raises the completed event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void OnCompleted(EventArgs e)
        {
            if (Completed != null)
            {
                Completed(this, e);
            }
        }

        private void OnErrorReceived(DataReceivedEventArgs e)
        {
            if (ErrorReceived != null)
            {
                ErrorReceived(this, e);
            }
        }

        public string ProjectPath
        {
            get { return _rake.ProjectPath; }
            set
            {
                if (_rake.ProjectPath != value)
                {
                    _rake.ProjectPath = value;
                }
            }
        }

        /// <summary>
        /// Runs all tests for the project.
        /// </summary>
        /// <param name="trace">Whether to show a stack trace</param>
        public void RunAllTests(bool trace)
        {
            RunRake(Resources.AllTests, trace);
        }

        /// <summary>
        /// Runs all unit tests for the project.
        /// </summary>
        /// <param name="trace">Whether to show a stack trace</param>
        public void RunAllUnitTests(bool trace)
        {
            RunRake(Resources.UnitTests, trace);
        }

        /// <summary>
        /// Runs all functional tests for the project.
        /// </summary>
        /// <param name="trace"></param>
        public void RunAllFunctionalTests(bool trace)
        {
            RunRake(Resources.FunctionalTests, trace);
        }

        /// <summary>
        /// Runs all integration tests for the project.
        /// </summary>
        /// <param name="trace"></param>
        public void RunAllIntegrationTests(bool trace)
        {
            RunRake(Resources.IntegrationTests, trace);
        }

        /// <summary>
        /// Runs tests for a single file.
        /// </summary>
        /// <param name="filePath"></param>
        public void RunTestsForFile(string filePath)
        {
            _ruby.RunCommand(filePath, true);
        }

        /// <summary>
        /// Runs tests for a directory.
        /// </summary>
        /// <param name="path">The directory path</param>
        public void RunTestsForDirectory(string path, bool trace)
        {
            switch(FileSystemService.GetTestableDirectory(path))
            {
                case TestableDirectory.AllTests :
                    RunAllTests(trace);
                    break;
                case TestableDirectory.UnitTests :
                    RunAllUnitTests(trace);
                    break;
                case TestableDirectory.FunctionalTests :
                    RunAllFunctionalTests(trace);
                    break;
                case TestableDirectory.IntegrationTests :
                    RunAllIntegrationTests(trace);
                    break;
                default :
                    return;
            }
        }

        /// <summary>
        /// Run rake, optionally with --trace specified
        /// </summary>
        /// <param name="arguments">Arguments to rake.</param>
        /// <param name="trace">If we want to run with a stack trace, append --trace.</param>
        private void RunRake(string arguments, bool trace)
        {
            if (trace)
            {
                arguments += Resources.Trace;
            }
            _rake.RunCommand(arguments, true);
        }

        /// <summary>
        /// Handles the OutputReceived event for the process.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void process_OutputReceived(object sender, DataReceivedEventArgs e)
        {
            OnOutputReceived(e);
        }

        /// <summary>
        /// Handles the Completed event for the process.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void process_Completed(object sender, EventArgs e)
        {
            OnCompleted(e);
        }

    }
}
